package com.kly.manager.websocket;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.json.JSONUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.kly.domain.entity.Message;
import com.kly.domain.entity.User;
import com.kly.domain.vo.UserVO;
import com.kly.manager.websocket.enums.UserChatMessageTypeEnum;
import com.kly.manager.websocket.model.ReceiverType;
import com.kly.manager.websocket.model.UserChatMessageRequest;
import com.kly.manager.websocket.model.UserChatMessageResponse;
import com.kly.service.MessageService;
import com.kly.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * @author admin
 * @date 2025/3/24
 */
@Configuration
@Slf4j
public class UserChatHandler extends TextWebSocketHandler {

    @Resource
    private UserService userService;
    /**
     * 定义用户聊天roomId websocket session
     */
    private final Map<Long, Set<WebSocketSession>> userChatSessionMap = new ConcurrentHashMap<>();


    @Resource
    private MessageService messageService;


    /**
     * 广播类
     */
    public void broadcastToUser(Long roomId, UserChatMessageResponse messageResponse, WebSocketSession excludeSession) throws IOException {
        Set<WebSocketSession> webSocketSessions = userChatSessionMap.get(roomId);
        if (CollUtil.isEmpty(webSocketSessions)) {
            return;
        }
        //     发送消息 精度损失问题 Long
        ObjectMapper objectMapper = new ObjectMapper();
        SimpleModule module = new SimpleModule();
        module.addSerializer(Long.class, ToStringSerializer.instance);
        module.addSerializer(Long.TYPE, ToStringSerializer.instance);
        objectMapper.registerModule(module);
        String msgJson = objectMapper.writeValueAsString(messageResponse);
        //     发送消息
        TextMessage textMessage = new TextMessage(msgJson);
        for (WebSocketSession webSocketSession : webSocketSessions) {
            if (webSocketSession.isOpen() && !webSocketSession.equals(excludeSession)) {
                webSocketSession.sendMessage(textMessage);
            }
        }
    }

    /**
     * 广播消息
     */
    public void broadcastToUser(Long roomId, UserChatMessageResponse messageResponse) throws IOException {
        broadcastToUser(roomId, messageResponse, null);
    }

    /**
     * 连接建立成功
     *
     * @param session
     * @throws Exception
     */
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        // 获取roomId loginUser
        Long roomId = (Long) session.getAttributes().get("roomId");
        User loginUser = (User) session.getAttributes().get("loginUser");

        userChatSessionMap.putIfAbsent(roomId, ConcurrentHashMap.newKeySet());
        userChatSessionMap.get(roomId).add(session);

        //     发送成功连接消息
        UserChatMessageResponse messageResponse = new UserChatMessageResponse();
        messageResponse.setType(UserChatMessageTypeEnum.INFO.getValue());
        String message = String.format("用户%s进入聊天室", loginUser.getUserName());
        messageResponse.setMessage(message);
        messageResponse.setUserVO(userService.getUserVo(loginUser));
        // 返回当前房间所有用户信息
        Set<WebSocketSession> webSocketSessions = userChatSessionMap.get(roomId);
        List<UserVO> userVOList = webSocketSessions.stream()
                .map(webSocketSession -> {
                    User user = (User) webSocketSession.getAttributes().get("loginUser");
                    return userService.getUserVo(user);
                }).collect(Collectors.toList());
        messageResponse.setUserVOList(userVOList);
        broadcastToUser(roomId, messageResponse);
    }


    /**
     * 处理消息
     *
     * @param session
     * @param message
     * @throws Exception
     */
    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        //     解析message
        UserChatMessageRequest userChatMessageRequest = JSONUtil.toBean(message.getPayload(), UserChatMessageRequest.class);
        String content = userChatMessageRequest.getContent();

        if (content == null) {
            return;
        }

        //     发送消息
        Long roomId = (long) session.getAttributes().get("roomId");
        User loginUser = (User) session.getAttributes().get("loginUser");
        UserChatMessageResponse messageResponse = new UserChatMessageResponse();
        messageResponse.setType(UserChatMessageTypeEnum.SEND_MESSAGE.getValue());
        messageResponse.setContent(content);
        messageResponse.setUserVO(userService.getUserVo(loginUser));


        //     保存用户发送信息
        Integer receiverType = (Integer) session.getAttributes().get("receiverType");
        if (Objects.equals(ReceiverType.GROUP.getValue(), receiverType)) {
            broadcastToUser(roomId, messageResponse, session);
            //     保存到消息表
            Message msg = new Message();
            msg.setSenderId(loginUser.getId());
            msg.setReceiverType(ReceiverType.GROUP.getValue());
            msg.setReceiverId(roomId);
            msg.setContent(content);
            messageService.save(msg);
        }

    }

    /**
     * 连接关闭
     *
     * @param session
     * @param status
     * @throws Exception
     */
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        // 获取roomId loginUser
        Long roomId = (Long) session.getAttributes().get("roomId");
        User loginUser = (User) session.getAttributes().get("loginUser");

        Set<WebSocketSession> webSocketSessions = userChatSessionMap.get(roomId);
        if (CollUtil.isNotEmpty(webSocketSessions)) {
            webSocketSessions.remove(session);
            if (CollUtil.isEmpty(webSocketSessions)) {
                userChatSessionMap.remove(roomId);
            }
        }

        //     发送退出消息
        UserChatMessageResponse messageResponse = new UserChatMessageResponse();
        messageResponse.setType(UserChatMessageTypeEnum.INFO.getValue());
        String message = String.format("用户%s退出聊天室", loginUser.getUserName());
        messageResponse.setMessage(message);
        messageResponse.setUserVO(userService.getUserVo(loginUser));
        broadcastToUser(roomId, messageResponse);
    }
}
